using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using User.Application.Contracts.Interfaces;

namespace User.Infrastructure
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly UserDbContext _context;
        private IDbContextTransaction? _currentTransaction;

        public UnitOfWork(UserDbContext context)
        {
            _context = context ?? throw new ArgumentNullException(nameof(context));
        }


        public void Dispose()
        {
            _context.Dispose();
        }

        public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            if (_currentTransaction != null)
            {
                return await _context.SaveChangesAsync(cancellationToken);
            }

            try
            {
                var result = await _context.SaveChangesAsync(cancellationToken);
                return result;
            }
            catch (DbUpdateConcurrencyException ex)
            {
                // Handle concurrency exceptions as needed
                throw new InvalidOperationException("Concurrency conflict occurred.", ex);
            }
            catch (Exception ex)
            {
                // Handle other exceptions as needed
                throw new InvalidOperationException("An error occurred while saving changes.", ex);
            }
        }

        public async Task BeginTransactionAsync()
        {
            if (_context.Database.CurrentTransaction != null)
            {
                throw new InvalidOperationException("A transaction is already in progress.");
            }

            _currentTransaction = await _context.Database.BeginTransactionAsync();
        }

        public async Task CommitTransactionAsync()
        {
            if (_currentTransaction == null)
            {
                throw new InvalidOperationException("No active transaction to commit.");
            }

            try
            {
                await _currentTransaction.CommitAsync();
                _currentTransaction.Dispose();
                _currentTransaction = null;
            }
            catch (Exception ex)
            {
                await RollbackTransactionAsync();
                throw new InvalidOperationException("An error occurred while committing the transaction.", ex);
            }
        }

        public async Task RollbackTransactionAsync()
        {
            if (_currentTransaction == null)
            {
                throw new InvalidOperationException("No active transaction to roll back.");
            }

            try
            {
                await _currentTransaction.RollbackAsync();
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("An error occurred while rolling back the transaction.", ex);
            }
            finally
            {
                _currentTransaction.Dispose();
                _currentTransaction = null;
            }
        }
    }
}